
#pragma once;

namespace FlameEngine
{
	class RenderOrder
	{
	public:
		inline void SetQueueId(uint32_t queueID)
		{
			int32_t queue = (m_sortValue & g_queueMask)>>g_queueOfsBit;
			queueID = (queueID>g_maxQueue)?g_maxQueueID:queueID;
			m_sortValue &= ~g_queueMask;
			m_sortValue |= (queueID<<g_queueOfsBit);
		}

		inline void SetPriority(uint32_t priority)
		{
			int32_t curPriority = (m_sortValue & g_priorityMask) >> g_priorityOfs;
			priority = (priority > g_maxPriority)?g_maxPriority:priority;
			m_sortValue &= ~g_priorityMask;
			m_sortValue |= (priority << g_priorityOfs);
		}

		inline void SetDistance(uint32_t distance)
		{
			m_dist = distance;
			m_sortValue |= (1<<63);
		}

		inline void SetPass(uint32_t pass)
		{
			int32_t curPass = (m_sortValue & g_passMask) >> g_passOfs;
			pass = (pass > g_maxPass)?g_maxPass:pass;
			m_sortValue &= ~g_passMask;
			m_sortValue |= (pass << g_passOfs);
		}

		inline void SetShaderId(uint32_t shaderId)
		{
			m_shaderID = shaderId;
			m_sortValue |= (1<<63);
		}

		inline void SetTransparent(bool transparent)
		{
			if(transparent)
				m_sortValue |= (1<<g_transparentOfs);
			else
				m_sortValue &= ~(1<<g_transparentOfs);

			m_sortValue |= (1<<63);
		}

		inline const uint64_t& GetRenderOrder()
		{
			if((m_sortValue&(1<<63)) > 0)
			{
				uint64_t transparentBit = 1<<g_transparentOfs;
				if((m_sortValue&transparentBit)>0)
				{
					uint64_t mask = g_shaderMask|g_distanceMask;
					m_sortValue &= ~mask;
					m_sortValue |= (m_dist<< (g_shaderOfs+g_distanceOfs));
				}
				else
				{
					uint64_t mask = g_shaderMask|g_distanceMask;
					m_sortValue &= ~mask;
					m_sortValue |= (m_shaderID<<g_shaderOfs);
					m_sortValue |= ((g_maxDistance-m_dist)<<g_distanceOfs);
				}
				m_sortValue &= ~(1<<63);
			}
			return m_sortValue;
		}

	private:
		uint64_t m_sortValue;
		uint16_t m_dist;
		uint16_t m_shaderID;

		static const uint64_t g_distanceMask = 0xffff;
		static const uint64_t g_shaderMask = 0x1FFF0000;
		static const uint64_t g_passMask = 0x60000000;
		static const uint64_t g_priorityMask = 0x7F80000000;
		static const uint64_t g_queueMask = 0x7F8000000000;

		static const uint8_t g_transparentOfs = 47;
		static const uint8_t g_queueOfs = 39;
		static const uint8_t g_priorityOfs = 31;
		static const uint8_t g_passOfs = 29;
		static const uint8_t g_shaderOfs = 16;
		static const uint8_t g_distanceOfs = 0;

		static const uint32_t g_maxQueue = 255;
		static const uint32_t g_maxPriority = 255;
		static const uint32_t g_maxPass = 3;
		static const uint32_t g_maxShader = 8191;
		static const uint32_t g_maxDistance = 65535;
	};
}